#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    GameData::importTextures();
    ui->setupUi(this);
    setFocusPolicy(Qt::StrongFocus);

    showFullScreen();
    setFixedSize(size());

    centerX = width() / 2;
    centerY = height() / 2;
    centerTileX = centerX - 32;
    centerTileY = centerY - 32;

    setUpMainMenuWidgets();
    setUpNewGameWidgets();
    setUpLoadGameWidgets();
    setUpSettingsWidgets();
    setUpPausedGameWidgets();

    curMap = NULL;
    player = NULL;
    inGame = false;

    cheatMode = false;
    cheatString = "qwerty";

    animTimer = new QTimer(this);
    animTimer->setInterval(20);
    connect(animTimer, SIGNAL(timeout()), this, SLOT(animTimerFire()));
    curFrame = BASE_FRAME;

    gameMusic = new Sound();
    gameMusic->initSounds();
    gameMusic->setMusic("maintheme");

    currentView = MainMenu;
    showMainMenuWidgets();
    repaint();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::loadUserAndStart(QString username) {
    player = GameData::importPlayerData(username);
    curMap = GameData::importMap("saves/" + username + "/maps/" + player->getCurMap());

    currentView = InGame;
    inGame = true;

    origX = centerTileX - (player->getPosX() * 64);
    origY = centerTileY - (player->getPosY() * 64);
    repaint();

    gameMusic->setMusic("ambience1", .5);
}

void MainWindow::switchMaps(QString newMapName, int linkCode) {
    // beta version ends if portal with link code 20 is reached
    if(linkCode == 20) {
        QMessageBox::information(this, "Victory!", "Congratulations! You have beaten Pyramid Escape Beta!\nKeep an eye out for the final version!");
        saveAndExit_clicked();
        return;
    }

    // switch maps
    GameData::exportMap(curMap, ("saves/" + player->getUsername() + "/maps/"));
    delete curMap;
    curMap = GameData::importMap("saves/" + player->getUsername() + "/maps/" + newMapName);

    // locate portal with correct link code
    EnvObject *object;
    PortalObject* portal;
    int portalX = -1, portalY;
    for(int x = 0; x < curMap->getWidth(); ++x) {
        for(int y = 0; y < curMap->getHeight(); ++y) {
            object = curMap->getTileAt(x,y)->getObject();

            if(object && object->getTexture().contains("portal")) {
                portal = dynamic_cast<PortalObject *>(object);

                if(portal->getLinkCode() == linkCode) {
                    portalX = x;
                    portalY = y;
                    break;
                }
            }
        }
        if(portalX > -1) break;
    }

    player->setCurMap(newMapName);
    player->setPosX(portalX);
    player->setPosY(portalY);

    origX = centerTileX - (portalX * 64);
    origY = centerTileY - (portalY * 64);
    repaint();
}

void MainWindow::playerMoved() {
    EnvObject *object = curMap->getTileAt(player->getPosX(), player->getPosY())->getObject();

    if(object) {
        QString objectTexture = object->getTexture();

        // if it's a portal, switch maps
        if(objectTexture.contains("portal")) {
            PortalObject *portal = dynamic_cast<PortalObject *>(object);

            switchMaps(portal->getDestinationMap(), portal->getLinkCode());
            Sound::playSound("portal");
        }
    }
}

void MainWindow::paintEvent(QPaintEvent *event) {
    QPainter painter(this);

    // black background
    painter.fillRect(0,0, width(), height(), Qt::black);

    //Movie background test

            //END Movie background test

    // paint depending on view
    if(inGame && currentView == InGame) {
        if(curMap != NULL) {
            Tile *tile;
            int mapWidth = curMap->getWidth();
            int mapHeight = curMap->getHeight();

            // floors
            for(int x = 0; x < mapWidth; ++x) {
                for(int y = 0; y < mapHeight; ++y) {
                    tile = curMap->getTileAt(x,y);

                    painter.drawPixmap((x * 64 + origX),(y * 64 + origY), *GameData::floorTextures[tile->getFloorType()]);
                }
            }

            // items
            for(int x = 0; x < mapWidth; ++x) {
                for(int y = 0; y < mapHeight; ++y) {
                    tile = curMap->getTileAt(x,y);
                    Item *item = tile->getItem();

                    if(item) painter.drawPixmap((x * 64 + origX),(y * 64 + origY), *GameData::itemTextures[item->getTexture()]);
                }
            }

            // lasers?


            // objects
            for(int x = 0; x < mapWidth; ++x) {
                for(int y = 0; y < mapHeight; ++y) {
                    tile = curMap->getTileAt(x,y);
                    EnvObject *object = tile->getObject();

                    if(object) painter.drawPixmap((x * 64 + origX),(y * 64 + origY), *GameData::objectTextures[object->getTexture()]);
                }
            }

            // walls
            QString wallType = curMap->getWallType();
            for(int x = 0; x < mapWidth; ++x) {
                for(int y = 0; y < mapHeight; ++y) {
                    tile = curMap->getTileAt(x,y);

                    if(tile->getWallB()) painter.drawPixmap((x * 64 + origX),((y + 1) * 64 - 8 + origY), *GameData::wallTextures[wallType + "H"]);
                    if(tile->getWallR()) painter.drawPixmap(((x + 1) * 64 - 8 + origX),(y * 64 + origY), *GameData::wallTextures[wallType + "V"]);
                }
            }

            // wall intersections
            Tile *tileB, *tileR;
            for(int x = 0; x < (mapWidth - 1); ++x) {
                for(int y = 0; y < (mapHeight - 1); ++y) {
                    tile = curMap->getTileAt(x,y); // current tile
                    tileB = curMap->getTileAt(x, y + 1); // tile Below current tile
                    tileR = curMap->getTileAt(x + 1, y); // tile to Right of current tile

                    if(tile->getWallB() && tile->getWallR() && tileR->getWallB() && tileB->getWallR()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "cross"]);
                    }
                    else if(tile->getWallB() && tile->getWallR() && tileR->getWallB()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "NP"]);
                    }
                    else if(tile->getWallB() && tile->getWallR() && tileB->getWallR()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "WP"]);
                    }
                    else if(tile->getWallB() && tileB->getWallR() && tileR->getWallB()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "SP"]);
                    }
                    else if(tile->getWallR() && tileR->getWallB() && tileB->getWallR()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "EP"]);
                    }
                    else if(tile->getWallB() && tile->getWallR()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "NW"]);
                    }
                    else if(tile->getWallB() && tileB->getWallR()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "SW"]);
                    }
                    else if(tileB->getWallR() && tileR->getWallB()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "SE"]);
                    }
                    else if(tile->getWallR() && tileR->getWallB()) {
                        painter.drawPixmap((x + 1) * 64 - 16 + origX, (y + 1) * 64 - 16 + origY, *GameData::wallTextures[wallType + "NE"]);
                    }
                }
            }

            // pivot doors!
            for(int x = 0; x < (mapWidth - 1); ++x) {
                for(int y = 0; y < (mapHeight - 1); ++y) {
                    tile = curMap->getTileAt(x,y);
                    QList<PivotDoor*>* pivotDoors = tile->getPivotDoors();

                    for(int i = 0; i < pivotDoors->size(); ++i) {
                        PivotDoor* door = pivotDoors->at(i);

                        if(door->getLocation() == PivotDoor::Top_Left) painter.drawPixmap(((x - 1) * 64 + 14 + origX),((y - 1) * 64 + 14 + origY), *GameData::doorTextures[door->getTexture()]);
                        else if(door->getLocation() == PivotDoor::Top_Right) painter.drawPixmap((x * 64 - 14 + origX),((y - 1) * 64 + 14 + origY), *GameData::doorTextures[door->getTexture()]);
                        else if(door->getLocation() == PivotDoor::Bottom_Right) painter.drawPixmap((x * 64 - 14 + origX),(y * 64 - 14 + origY), *GameData::doorTextures[door->getTexture()]);
                        else if(door->getLocation() == PivotDoor::Bottom_Left) painter.drawPixmap(((x - 1) * 64 + 14 + origX),(y * 64 - 14 + origY), *GameData::doorTextures[door->getTexture()]);
                    }
                }
            }

            // draw current frame of avatar in center of screen
            if(player->getDirection() == Player::North) painter.drawPixmap(centerTileX, centerTileY, *GameData::avatarN[curFrame]);
            else if(player->getDirection() == Player::East) painter.drawPixmap(centerTileX, centerTileY, *GameData::avatarE[curFrame]);
            else if(player->getDirection() == Player::South) painter.drawPixmap(centerTileX, centerTileY, *GameData::avatarS[curFrame]);
            else if(player->getDirection() == Player::West) painter.drawPixmap(centerTileX, centerTileY, *GameData::avatarW[curFrame]);
        }
    }

    // else, not in game
    else {
        // paint logo
        int x = centerX - (GameData::interfaceTextures["logo"]->width() / 2);
        painter.drawPixmap(x, 0, *GameData::interfaceTextures["logo"]);
    }



}

void MainWindow::mousePressEvent(QMouseEvent *event) {

}

void MainWindow::keyPressEvent(QKeyEvent *event) {
    int key = event->key();

    // cheat mode activation
    if(currentView == Settings) {
        if(key == Qt::Key_Enter || key == Qt::Key_Return) cheatString = "";
        else {
            cheatString += event->text();

            if(cheatString == "iamamummy") {
                cheatMode = true;
                Sound::playSound("mummy");
            }
        }
    }

    // handle in-game keystrokes
    if(!inGame || animTimer->isActive()) return;

    if(key == Qt::Key_Escape) {
        if(currentView == Paused) {
            resumeGame_clicked();
        } else {
            currentView = Paused;
            showPausedGameWidgets();
            repaint();

        }
        Sound::playSound("click");
    }
    else if(currentView == InGame) {
        if(key == Qt::Key_W) {
            // turn player and repaint
            player->setDirection(Player::North);
            repaint();

            // check for valid move; if not, return
            int posX = player->getPosX();
            int posY = player->getPosY();
            int aheadX = posX;
            int aheadY = posY - 1;

            if(aheadY < 0) return;
            Tile *aheadTile = curMap->getTileAt(aheadX, aheadY);

            if(aheadTile->getWallB()) return;

            EnvObject *object = aheadTile->getObject();
            if(object) {
                // if object is not walkable
                if(!object->isWalkable()) {
                    // if object is a boulder & boulder is pushable, push
                    if(object->getTexture().contains("boulder")) {
                        // check for boulder pushability
                        int newBPosX = aheadX;
                        int newBPosY = aheadY - 1;

                        if(newBPosY < 0) return;
                        Tile *newBTile = curMap->getTileAt(newBPosX, newBPosY);

                        if(newBTile->getWallB()) return;
                        if(newBTile->getObject()) return;
                        if(newBTile->getItem()) return;

                        // push boulder
                        aheadTile->setObject(NULL);
                        newBTile->setObject(object);
                        repaint();
                        Sound::playSound("boulder");
                    }
                    // else return
                    else return;
                }
            }

            // move
            player->setPosY(aheadY);
            animTimer->start();
        }
        else if(key == Qt::Key_A) {
            // turn player and repaint
            player->setDirection(Player::West);
            repaint();

            // check for valid move; if not, return
            int posX = player->getPosX();
            int posY = player->getPosY();
            int aheadX = posX - 1;
            int aheadY = posY;

            if(aheadX < 0) return;
            Tile *aheadTile = curMap->getTileAt(aheadX, aheadY);

            if(aheadTile->getWallR()) return;

            EnvObject *object = aheadTile->getObject();
            if(object) {
                // if object is not walkable
                if(!object->isWalkable()) {
                    // if object is a boulder & boulder is pushable, push
                    if(object->getTexture().contains("boulder")) {
                        // check for boulder pushability
                        int newBPosX = aheadX - 1;
                        int newBPosY = aheadY;

                        if(newBPosX < 0) return;
                        Tile *newBTile = curMap->getTileAt(newBPosX, newBPosY);

                        if(newBTile->getWallR()) return;
                        if(newBTile->getObject()) return;
                        if(newBTile->getItem()) return;

                        // push boulder
                        aheadTile->setObject(NULL);
                        newBTile->setObject(object);
                        repaint();
                        Sound::playSound("boulder");
                    }
                    // else return
                    else return;
                }
            }

            // move
            player->setPosX(aheadX);
            animTimer->start();
        }
        else if(key == Qt::Key_S) {
            // turn player and repaint
            player->setDirection(Player::South);
            repaint();

            // check for valid move; if not, return
            int posX = player->getPosX();
            int posY = player->getPosY();
            int aheadX = posX;
            int aheadY = posY + 1;

            if(aheadY >= curMap->getHeight()) return;
            Tile *aheadTile = curMap->getTileAt(aheadX, aheadY);

            if(curMap->getTileAt(posX, posY)->getWallB()) return;

            EnvObject *object = aheadTile->getObject();
            if(object) {
                // if object is not walkable
                if(!object->isWalkable()) {
                    // if object is a boulder & boulder is pushable, push
                    if(object->getTexture().contains("boulder")) {
                        // check for boulder pushability
                        int newBPosX = aheadX;
                        int newBPosY = aheadY + 1;

                        if(newBPosY >= curMap->getHeight()) return;
                        Tile *newBTile = curMap->getTileAt(newBPosX, newBPosY);

                        if(aheadTile->getWallB()) return;
                        if(newBTile->getObject()) return;
                        if(newBTile->getItem()) return;

                        // push boulder
                        aheadTile->setObject(NULL);
                        newBTile->setObject(object);
                        repaint();
                        Sound::playSound("boulder");
                    }
                    // else return
                    else return;
                }
            }

            // move
            player->setPosY(aheadY);
            animTimer->start();
        }
        else if(key == Qt::Key_D) {
            // turn player and repaint
            player->setDirection(Player::East);
            repaint();

            // check for valid move; if not, return
            int posX = player->getPosX();
            int posY = player->getPosY();
            int aheadX = posX + 1;
            int aheadY = posY;

            if(aheadX >= curMap->getWidth()) return;
            Tile *aheadTile = curMap->getTileAt(aheadX, aheadY);

            if(curMap->getTileAt(posX, posY)->getWallR()) return;

            EnvObject *object = aheadTile->getObject();
            if(object) {
                // if object is not walkable
                if(!object->isWalkable()) {
                    // if object is a boulder & boulder is pushable, push
                    if(object->getTexture().contains("boulder")) {
                        // check for boulder pushability
                        int newBPosX = aheadX + 1;
                        int newBPosY = aheadY;

                        if(newBPosX >= curMap->getWidth()) return;
                        Tile *newBTile = curMap->getTileAt(newBPosX, newBPosY);

                        if(aheadTile->getWallR()) return;
                        if(newBTile->getObject()) return;
                        if(newBTile->getItem()) return;

                        // push boulder
                        aheadTile->setObject(NULL);
                        newBTile->setObject(object);
                        repaint();
                        Sound::playSound("boulder");
                    }
                    // else return
                    else return;
                }
            }

            // move
            player->setPosX(aheadX);
            animTimer->start();
        }

        // if F is pressed, pick up item (if there is one)
        else if(key == Qt::Key_F) {
            Tile *tile = curMap->getTileAt(player->getPosX(), player->getPosY());
            Item *item = tile->getItem();

            if(item) {
                tile->setItem(NULL);
                player->getInventory()->push_back(item);
                repaint();
                Sound::playSound("key");
            }
        }

        // if E is pressed, attempt to activate object ahead (if there is one)
        else if(key == Qt::Key_E) {
            Tile *aheadTile;

            switch(player->getDirection()) {
                case Player::North:
                    if((player->getPosY() - 1) < 0) return;
                    aheadTile = curMap->getTileAt(player->getPosX(), player->getPosY() - 1);
                    break;
                case Player::East:
                    if((player->getPosX() + 1) >= curMap->getWidth()) return;
                    aheadTile = curMap->getTileAt(player->getPosX() + 1, player->getPosY());
                    break;
                case Player::South:
                    if((player->getPosY() + 1) >= curMap->getHeight()) return;
                    aheadTile = curMap->getTileAt(player->getPosX(), player->getPosY() + 1);
                    break;
                case Player::West:
                    if((player->getPosX() - 1) < 0) return;
                    aheadTile = curMap->getTileAt(player->getPosX() - 1, player->getPosY());
                    break;
            }

            EnvObject *object = aheadTile->getObject();

            // if there is an object ahead, parse action
            if(object) {
                QString objTexture = object->getTexture();

                // if it is a gate (and not a laser activated gate)
                if(objTexture.contains("gate") && objTexture != "gateLA") {
                    QString gateNum = objTexture.remove("gate");
                    bool playerHasKey = false;

                    // search player inventory for right key
                    QList<Item *> *playerInventory = player->getInventory();
                    Item *item;
                    QString itemTexture;
                    for(int i = 0; i < playerInventory->size(); ++i) {
                        item = playerInventory->at(i);
                        itemTexture = item->getTexture();

                        if(itemTexture.contains("key") && itemTexture.remove("key") == gateNum) {
                            playerHasKey = true;
                            break;
                        }
                    }

                    if(playerHasKey || cheatMode) {
                        delete object;
                        aheadTile->setObject(NULL);
                        repaint();
                        Sound::playSound("gate");
                    }
                    else {
                        Sound::playSound("locked");
                    }
                }
            }
        }
    }
}

void MainWindow::focusOutEvent(QFocusEvent *event) {

}

void MainWindow::closeEvent(QCloseEvent *event) {
    int response = QMessageBox::information(this, "Pyramid Escape", "Are you sure you want to exit?", QMessageBox::Yes, QMessageBox::No);
    if(response == QMessageBox::No) event->ignore();
}

// main menu screen
void MainWindow::setUpMainMenuWidgets() {
    lblNewGame = new MenuLabel("New Game", centerX, 550, this);
    lblLoadGame = new MenuLabel("Load Game", centerX, 600, this);
    lblMainSettings = new MenuLabel("Settings", centerX, 650, this);
    lblExit = new MenuLabel("Exit", centerX, 700, this);

    connect(lblNewGame, SIGNAL(clicked()), this, SLOT(newGame_clicked()));
    connect(lblLoadGame, SIGNAL(clicked()), this, SLOT(loadGame_clicked()));
    connect(lblMainSettings, SIGNAL(clicked()), this, SLOT(mainSettings_clicked()));
    connect(lblExit, SIGNAL(clicked()), this, SLOT(exit_clicked()));
}

void MainWindow::showMainMenuWidgets() {
    QDir savesDir("saves");
    if(savesDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).isEmpty()) lblLoadGame->setDisabled(true);
    else lblLoadGame->setEnabled(true);

    lblNewGame->show();
    lblLoadGame->show();
    lblMainSettings->show();
    lblExit->show();
}

void MainWindow::hideMainMenuWidgets() {
    lblNewGame->hide();
    lblLoadGame->hide();
    lblMainSettings->hide();
    lblExit->hide();
}

// new game screen
void MainWindow::setUpNewGameWidgets() {
    txtUserName = new MenuLineEdit("Your name: ", centerX, 550, this);

    QStringList options;
    options << "Easy" << "Medium" << "Hard";
    selDifficulty = new MenuSelecter("Difficulty: ", options, 1, centerX, 600, this);

    lblStartGame = new MenuLabel("Start Game!", centerX, 650, this);
    lblBackFromNew = new MenuLabel("Back", centerX, 700, this);

    connect(lblStartGame, SIGNAL(clicked()), this, SLOT(startGame_clicked()));
    connect(lblBackFromNew, SIGNAL(clicked()), this, SLOT(backFromNew_clicked()));
}

void MainWindow::showNewGameWidgets() {
    txtUserName->clear();
    selDifficulty->setToDefault();

    txtUserName->show();
    selDifficulty->show();
    lblStartGame->show();
    lblBackFromNew->show();
}

void MainWindow::hideNewGameWidgets() {
    txtUserName->hide();
    selDifficulty->hide();
    lblStartGame->hide();
    lblBackFromNew->hide();
}

// load game screen
void MainWindow::setUpLoadGameWidgets() {
    QDir savesDir("saves");
    QStringList saves = savesDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
    boxNameSelect = new MenuComboBox("Select save file: ", saves, centerX, 550, this);

    lblLoadAndStart = new MenuLabel("Load and Start!", centerX, 600, this);
    lblBackFromLoad = new MenuLabel("Back", centerX, 650, this);

    connect(lblLoadAndStart, SIGNAL(clicked()), this, SLOT(loadAndStart_clicked()));
    connect(lblBackFromLoad, SIGNAL(clicked()), this, SLOT(backFromLoad_clicked()));
}

void MainWindow::showLoadGameWidgets() {
    QDir savesDir("saves");
    boxNameSelect->setNewOptions(savesDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot));

    boxNameSelect->show();
    lblLoadAndStart->show();
    lblBackFromLoad->show();
}

void MainWindow::hideLoadGameWidgets() {
    boxNameSelect->hide();
    lblLoadAndStart->hide();
    lblBackFromLoad->hide();
}

// settings view
void MainWindow::setUpSettingsWidgets() {
    QStringList options;
    options << "ON" << "OFF";
    int init;

    if(Sound::soundEnabled()) init = 0;
    else init = 1;
    selSoundEnabled = new MenuSelecter("Sound: ", options, init, centerX, 550, this);

    if(Sound::musicEnabled()) init = 0;
    else init = 1;
    selMusicEnabled = new MenuSelecter("Music: ", options, init, centerX, 600, this);

    lblBackFromSettings = new MenuLabel("Back", centerX, 650, this);

    connect(selSoundEnabled, SIGNAL(changed(QString)), this, SLOT(soundEnabled_changed(QString)));
    connect(selMusicEnabled, SIGNAL(changed(QString)), this, SLOT(musicEnabled_changed(QString)));
    connect(lblBackFromSettings, SIGNAL(clicked()), this, SLOT(backFromSettings_clicked()));
}

void MainWindow::showSettingsWidgets() {
    selSoundEnabled->show();
    selMusicEnabled->show();
    lblBackFromSettings->show();
}

void MainWindow::hideSettingsWidgets() {
    selSoundEnabled->hide();
    selMusicEnabled->hide();
    lblBackFromSettings->hide();
}

// paused game view
void MainWindow::setUpPausedGameWidgets() {
    lblResumeGame = new MenuLabel("Resume", centerX, 550, this);
    lblPausedSettings = new MenuLabel("Settings", centerX, 600, this);
    lblSaveAndExit = new MenuLabel("Save and Exit", centerX, 650, this);

    connect(lblResumeGame, SIGNAL(clicked()), this, SLOT(resumeGame_clicked()));
    connect(lblPausedSettings, SIGNAL(clicked()), this, SLOT(pausedSettings_clicked()));
    connect(lblSaveAndExit, SIGNAL(clicked()), this, SLOT(saveAndExit_clicked()));
}

void MainWindow::showPausedGameWidgets() {
    lblResumeGame->show();
    lblPausedSettings->show();
    lblSaveAndExit->show();
}

void MainWindow::hidePausedGameWidgets() {
    lblResumeGame->hide();
    lblPausedSettings->hide();
    lblSaveAndExit->hide();
}

// main menu view slots
void MainWindow::newGame_clicked() {
    currentView = NewGame;
    hideMainMenuWidgets();
    showNewGameWidgets();
}

void MainWindow::loadGame_clicked() {
    currentView = LoadGame;
    hideMainMenuWidgets();
    showLoadGameWidgets();
}

void MainWindow::mainSettings_clicked() {
    currentView = Settings;
    hideMainMenuWidgets();
    showSettingsWidgets();
}

void MainWindow::exit_clicked() {
    close();
}

// new game view slots
void MainWindow::startGame_clicked() {
    QString username = txtUserName->getText();
    QString difficulty = selDifficulty->getSelection();

    if(username.trimmed() == "") {
        QMessageBox::information(this, "Invalid Username", "Please enter a valid username.");
        txtUserName->clear();
        return;
    }

    QDir saveDir("saves/" + username);

    if(saveDir.exists()) {
        int response = QMessageBox::information(this, "Name Exists", "Would you like to overwrite the name \"" + username + "\"?", QMessageBox::Yes, QMessageBox::No);

        if(response == QMessageBox::Yes) {
            GameData::removeDir(saveDir.path());
        }
        else if(response == QMessageBox::No) {
            return;
        }
    }

    // create save file
    saveDir.setPath("saves");
    saveDir.mkdir(username);
    saveDir.cd(username);
    saveDir.mkdir("maps");

    // copy over maps files
    GameData::copyDir("maps", saveDir.filePath("maps"));

    // create user data file
    QFile dataFile(saveDir.filePath("data.dat"));

    // write out data
    dataFile.open(QIODevice::WriteOnly);
    QDataStream out(&dataFile);
    out.setVersion(QDataStream::Qt_4_6);

    if(difficulty == "Easy") out << Player::Easy; // write difficulty level
    else if(difficulty == "Medium") out << Player::Medium;
    else if(difficulty == "Hard") out << Player::Hard;
    out << QString("level1"); // initial map
    out << 0 << 0; // initial position
    out << Player::South; // initial direction
    out << 0; // size of inventory (initially no items)

    // close the file
    dataFile.close();

    hideNewGameWidgets();
    loadUserAndStart(username);
}

void MainWindow::backFromNew_clicked() {
    currentView = MainMenu;
    hideNewGameWidgets();
    showMainMenuWidgets();
}

// load game view slots
void MainWindow::backFromLoad_clicked() {
    currentView = MainMenu;
    hideLoadGameWidgets();
    showMainMenuWidgets();
}

void MainWindow::loadAndStart_clicked() {
    hideLoadGameWidgets();
    loadUserAndStart(boxNameSelect->getSelection());
}

// settings view slots
void MainWindow::soundEnabled_changed(QString newSelection) {
    if(newSelection == "ON") Sound::setSoundEnabled(true);
    else Sound::setSoundEnabled(false);
}

void MainWindow::musicEnabled_changed(QString newSelection) {
    if(newSelection == "ON") {
        Sound::setMusicEnabled(true);
        gameMusic->play();
    }
    else {
        Sound::setMusicEnabled(false);
        gameMusic->pause();
    }
}

void MainWindow::backFromSettings_clicked() {
    if(inGame) {
        currentView = Paused;
        hideSettingsWidgets();
        showPausedGameWidgets();
    }
    else {
        currentView = MainMenu;
        hideSettingsWidgets();
        showMainMenuWidgets();
    }
}

// paused game view slots
void MainWindow::resumeGame_clicked() {
    hidePausedGameWidgets();
    currentView = InGame;
    repaint();
}

void MainWindow::pausedSettings_clicked() {
    hidePausedGameWidgets();
    showSettingsWidgets();
    currentView = Settings;
}

void MainWindow::saveAndExit_clicked() {
    GameData::exportMap(curMap, ("saves/" + player->getUsername() + "/maps/"));
    GameData::exportSaveFile(player);

    delete curMap;
    delete player;
    curMap = NULL;
    player = NULL;

    inGame = false;
    hidePausedGameWidgets();
    showMainMenuWidgets();
    currentView = MainMenu;
    repaint();
    gameMusic->setMusic("maintheme");
}

// other
void MainWindow::animTimerFire() {
    if(++curFrame > 15) curFrame = 0;

    if(curFrame == BASE_FRAME) {
        animTimer->stop();
        playerMoved(); // process movement
    }

    // following line only necessary in beta:
    if(!inGame) return;

    int direction = player->getDirection();
    if(direction == Player::North) {
        origY += 4;
    } else if(direction == Player::East) {
        origX -= 4;
    } else if(direction == Player::South) {
        origY -= 4;
    } else if(direction == Player::West) {
        origX += 4;
    }

    repaint();
}
